#ifndef CPPPRIMER5THCHAPTER18
#define CPPPRIMER5THCHAPTER18
#include <cstdlib>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <stdexcept>

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

// #define NDEBUG

template <typename T>
int rangeForContainer(T &a)
{
    for (auto b : a)
    {
        cout << b << ",";
    }
    cout << endl;
    return 0;
}

// Exercises Section 18.1.1
// Exercise 18.1: What is the type of the exception object in the following
// throws?
// (a) range_error r("error");
// throw r;
// (b) exception *p = &r;
// throw *p;
// What would happen if the throw in (b) were written as throw p?
// Answer: (1) in (a) r is range_error; in (b) *p is exception; (2) cannot throw p.
int exercise18_1();

// Exercise 18.2: Explain what happens if an exception occurs at the indicated
// point:
// void exercise(int *b, int *e)
// {
//  vector<int> v(b, e);
//  int *p = new int[v.size()];
//  ifstream in("ints");
//  // exception occurs here
// }
// Answer: when exception occurs in that point, vector<int> and ifsteam will be destoryed by their destructor.
// however, p will be destructed, but the newed int pointed by p won't be deleted.
int exercise18_2();

// Exercise 18.3: There are two ways to make the previous code work
// correctly if an exception is thrown. Describe them and implement them.
int exercise18_3();

// Exercises Section 18.1.2
// Exercise 18.4: Looking ahead to the inheritance hierarchy in Figure 18.1 (p.
// 783), explain what’s wrong with the following try block. Correct it.
// try {
//  // use of the C++ standard library
// } catch(exception) {
//  // ...
// } catch(const runtime_error &re) {
//  // ...
// } catch(overflow_error eobj) { /* ... */ }
// Answer: change the order of exception and overflow_error
int exercise18_4();

// Exercise 18.5: Modify the following main function to catch any of the
// exception types shown in Figure 18.1 (p. 783):
// int main() {
//  // use of the C++ standard library
// }
// The handlers should print the error message associated with the exception before
// calling abort (defined in the header cstdlib) to terminate main.
int exercise18_5();

// Exercise 18.6: Given the following exception types and catch clauses,
// write a throw expression that creates an exception object that can be caught
// by each catch clause:
// (a) class exceptionType { };
// catch(exceptionType *pet) { }
// (b) catch(...) { }
// (c) typedef int EXCPTYPE;
// catch(EXCPTYPE) { }
int exercise18_6();

// Exercises Section 18.1.3
// Exercise 18.7: Define your Blob and BlobPtr classes from Chapter 16 to
// use function try blocks for their constructors.
// Answer: done for Blob.
int exercise18_7();

// Exercises Section 18.1.4
// Exercise 18.8: Review the classes you’ve written and add appropriate
// exception specifications to their constructors and destructors. If you think one
// of your destructors might throw, change the code so that it cannot throw.
// Answer: not interested.
int exercise18_8();

// Exercises Section 18.1.5
// Exercise 18.9: Define the bookstore exception classes described in this
// section and rewrite your Sales_data compound assigment operator to
// throw an exception.
// Answer: not interested.
int exercise18_9();

// Exercise 18.10: Write a program that uses the Sales_data addition
// operator on objects that have differing ISBNs. Write two versions of the
// program: one that handles the exception and one that does not. Compare the
// behavior of the programs so that you become familiar with what happens
// when an uncaught exception occurs.
// Answer: not interested.
int exercise18_10();

// Exercise 18.11: Why is it important that the what function doesn’t throw?
// Answer: (1)避免在异常处理过程中引发新的异常：如果what函数本身抛出异常，那么在处理一个异常的过程中就可能会触发另一个异常，这会导致异常处理逻辑变得复杂和混乱，难以维护和理解。
// (2) 保持控制流的简单性和可预测性：异常处理机制的一个重要目标是保持程序控制流的清晰和可预测。如果what函数抛出异常，那么程序的控制流就会变得更加难以预测，因为需要在异常处理代码中处理what函数可能抛出的异常。
// (3) 减少代码复杂性和出错可能性：如果what函数抛出异常，那么异常处理代码就需要处理这种额外的异常情况，这会增加代码的复杂性和出错的可能性。而what函数不抛出异常，可以简化异常处理代码，降低出错的风险。
int exercise18_11();

// Exercises Section 18.2.1
// Exercise 18.12: Organize the programs you have written to answer the
// questions in each chapter into their own namespaces. That is, namespace
// chapter15 would contain code for the Query programs and chapter10
// would contain the TextQuery code. Using this structure, compile the Query
// code examples.
// Answer: not interested.
int exercise18_12();

// Exercise 18.13: When might you use an unnamed namespace?
// Answer: The use of file static declarations is deprecated by the C++ standard.
// File statics should be avoided and unnamed namespaces used instead.
int exercise18_13();

namespace mathLib
{
    namespace MatrixLib
    {
        class matrix
        {
            friend std::ostream &operator<<(std::ostream &, const mathLib::MatrixLib::matrix &);
            friend matrix operator*(const matrix &, const matrix &);

        public:
            int i, j;
            matrix(int a = 2, int b = 1) : i(a), j(b) {}
        };
        std::ostream &operator<<(std::ostream &, const mathLib::MatrixLib::matrix &);
        matrix operator*(const matrix &, const matrix &);
    }
}
// Exercise 18.14 : Suppose we have the following declaration of the
//                  operator* that is a member of the nested namespace mathLib::MatrixLib :
// namespace mathLib
// {
//     namespace MatrixLib
//     {
//         class matrix
//         { /* ... */
//         };
//         matrix operator*(const matrix &, const matrix &);
// ... }
// }
//  How would you declare this operator in global scope ?
int exercise18_14();

// Exercises Section 18.2.2
// Exercise 18.15: Explain the differences between using declarations and
// directives.
// 总的来说，"using declaration"和"using directive"在C++中提供了不同的方式来简化对命名空间中名称的访问。
// 然而，它们在使用时需要谨慎，以避免潜在的名称冲突和其他问题。
// 在大型项目或库中，通常更倾向于避免使用"using directive"，以减少名称冲突的风险，并通过明确的命名空间前缀来提高代码的可读性和可维护性。
int exercise18_15();

// namespace Exercise
// {
//     int ivartian = 0;
//     double dvartian = 0;
//     const int limittian = 1000;
// }
// int ivartian = 0;
// // position 1
// void manip();
// void manip1();

// Exercise 18.16: Explain the following code assuming using declarations for
// all the members of namespace Exercise are located at the location labeled
// position 1. What if they appear at position 2 instead? Now answer the same
// question but replace the using declarations with a using directive for
// namespace Exercise.
// namespace Exercise
// {
//     int ivar = 0;
//     double dvar = 0;
//     const int limit = 1000;
// }
// int ivar = 0;
// // position 1
// void manip()
// {
//     // position 2
//     double dvar = 3.1416;
//     int iobj = limit + 1;
//     ++ivar;
//     ++::ivar;
// }
int exercise18_16();

// Exercise 18.17: Write code to test your answers to the previous question.
int exercise18_17();

template <typename T>
void swap(T v1, T v2)
{
    using std::swap;
    cout << "normal version swap. \n";
    // swap(v1.mem1, v2.mem1);
    swap(v1, v2);
    // swap remaining members of type T
}

// Exercises Section 18.2.3
// Exercise 18.18: Given the following typical definition of swap § 13.3 (p.
// 517), determine which version of swap is used if mem1 is a string. What if
// mem1 is an int? Explain how name lookup works in both cases.
// void swap(T v1, T v2)
// {
//     using std::swap;
//     swap(v1.mem1, v2.mem1);
//     // swap remaining members of type T
// }
int exercise18_18();

// Exercise 18.19: What if the call to swap was std::swap(v1.mem1, v2.mem1)?
// Answer: it will use std::swap.
int exercise18_19();

namespace primerLib
{
    inline void compute() { cout << "1 \n"; }
    inline void compute(const void *) { cout << "2 \n"; }
}

// comment this line when calling f1.
// using primerLib::compute;
inline void compute(int) { cout << "3 \n"; }
inline void compute(double, double = 3.4) { cout << "4 \n"; }
inline void compute(char *, char * = 0) { cout << "5 \n"; }
inline void f()
{
    // calling compute(int)
    compute(0);
}

inline void f1()
{
    using primerLib::compute;
    // calling compute(const void *)
    compute(0);
}

// Exercises Section 18.2.4
// Exercise 18.20: In the following code, determine which function, if any,
// matches the call to compute. List the candidate and viable functions. What
// type conversions, if any, are applied to the argument to match the parameter
// in each viable function?
// namespace primerLib {
//  void compute(); void compute(const void *);
// }
// using primerLib::compute;
// void compute(int);
// void compute(double, double = 3.4);
// void compute(char*, char* = 0);
// void f()
// {
//  compute(0);
// }
// What would happen if the using declaration were located in main before the call
// to compute? Answer the same questions as before.
int exercise18_20();

// Exercises Section 18.3.1
// Exercise 18.21: Explain the following declarations. Identify any that are in
// error and explain why they are incorrect:
// (a) class CADVehicle : public CAD, Vehicle { ... }; OK, vehicle will be default private.
// (b) class DblList: public List, public List { ... }; NOT OK, base class can only appear ONCE.
// (c) class iostream: public istream, public ostream { ...}; seems ok.
int exercise18_21();

class A
{
public:
    A() { cout << a << "\n"; }
    virtual inline int get() { return a; }

private:
    int a = 1;
};
class B : public A
{
public:
    B() { cout << b << "\n"; }
    inline int get() override { return b; }

private:
    int b = 2;
};
class C : public B
{
public:
    C() { cout << c << "\n"; }
    inline int get() override { return c; }

private:
    int c = 3;
};
class X
{
public:
    X() { cout << x << "\n"; }
    virtual inline int get() { return x; }

private:
    int x = 4;
};
class Y
{
public:
    Y() { cout << y << "\n"; }
    virtual inline int get() { return y; }

private:
    int y = 5;
};
class Z : public X, public Y
{
public:
    Z() { cout << z << "\n"; }
    inline int get() override { return z; }

private:
    int z = 6;
};
class MI : public C, public Z
{
public:
    MI() { cout << mi << "\n"; }
    inline int get() override { return mi; }

private:
    int mi = 7;
};

// Exercise 18.22: Given the following class hierarchy, in which each class defines a default constructor:
// class A { ... };
// class B : public A { ... };
// class C : public B { ... };
// class X { ... };
// class Y { ... };
// class Z : public X, public Y { ... };
// class MI : public C, public Z { ... };
// what is the order of constructor execution for the following definition?
// MI mi;
int exercise18_22();

class D : public X, public C
{
public:
    D() { cout << d << "\n"; }
    inline int get() override { return d; }

private:
    int d = 8;
};

// Exercises Section 18.3.2
// Exercise 18.23: Using the hierarchy in exercise 18.22 along with class D
// defined below, and assuming each class defines a default constructor, which,
// if any, of the following conversions are not permitted?
// class D : public X, public C { ... };
// D *pd = new D;
// (a) X *px = pd;
// (b) A *pa = pd;
// (c) B *pb = pd;
// (d) C *pc = pd;
int exercise18_23();

class Endangered
{
public:
    virtual ~Endangered()
    {
        std::cout << "Endangered dtor" << std::endl;
    }
    virtual std::ostream &print() const
    {
        return std::cout << "Endangered::print" << std::endl;
    }
    virtual void highlight() const
    {
        std::cout << "Endangered::highlight" << std::endl;
    }
    virtual double max_weight() const
    {
        std::cout << "Endangered::max_weight" << std::endl;
        return 0;
    }
    // . . .
};

class ZooAnimal;
extern std::ostream &
operator<<(std::ostream &, const ZooAnimal &);

class ZooAnimal
{
public:
    ZooAnimal() = default;
    ZooAnimal(std::string animal, bool exhibit,
              std::string family) : nm(animal),
                                    exhibit_stat(exhibit),
                                    fam_name(family) {}
    virtual ~ZooAnimal()
    {
        std::cout << "Animal dtor" << std::endl;
    }

    virtual std::ostream &print() const
    {
        return std::cout << "Animal::print" << std::endl;
    }
    virtual int population() const
    {
        std::cout << "Animal::population" << std::endl;
        return 0;
    }
    virtual double max_weight() const
    {
        std::cout << "Animal::max_weight" << std::endl;
        return 0;
    }

    // accessors
    std::string name() const { return nm; }
    std::string family_name() const { return fam_name; }
    bool onExhibit() const { return exhibit_stat; }
    // . . .
protected:
    std::string nm;
    bool exhibit_stat = false;
    std::string fam_name;
    // . . .
private:
};

using DanceType = unsigned;
constexpr DanceType two_left_feet = 0;
constexpr DanceType Astaire = 1;
constexpr DanceType Rogers = 42;

class Bear : public ZooAnimal
{
public:
    Bear() = default;
    Bear(std::string name, bool onExhibit = true,
         std::string family = "Bear") : ZooAnimal(name, onExhibit, family),
                                        dancetype(two_left_feet) {}

    virtual std::ostream &print() const
    {
        return std::cout << "Bear::print" << std::endl;
    }
    virtual int toes() const
    {
        std::cout << "Bear::toes" << std::endl;
        return 0;
    }
    int mumble(int)
    {
        std::cout << "Bear::mumble" << std::endl;
        return 0;
    }
    void dance(DanceType) const
    {
        std::cout << "Bear::dance" << std::endl;
    }

    virtual ~Bear()
    {
        std::cout << "Bear dtor" << std::endl;
    }

private:
    DanceType dancetype = Rogers;
};

class Panda : public Bear, public Endangered
{
public:
    Panda() = default;
    Panda(std::string name, bool onExhibit = true);
    virtual ~Panda()
    {
        std::cout << "Panda dtor" << std::endl;
    }
    virtual std::ostream &print() const
    {
        return std::cout << "Panda::print" << std::endl;
    }
    void highlight()
    {
        std::cout << "Panda::highlight" << std::endl;
    }
    virtual int toes()
    {
        std::cout << "Panda::toes" << std::endl;
        return 0;
    }
    virtual void cuddle()
    {
        std::cout << "Panda::cuddle" << std::endl;
    }
    virtual double max_weight() const;
    // . . .
};

inline Panda::Panda(std::string name, bool onExhibit)
    : Bear(name, onExhibit, "Panda") {}

inline double Panda::max_weight() const
{
    return std::max(ZooAnimal::max_weight(),
                    Endangered::max_weight());
}

// Exercise 18.24: On page 807 we presented a series of calls made through
// a Bear pointer that pointed to a Panda object. Explain each call assuming
// we used a ZooAnimal pointer pointing to a Panda object instead.
int exercise18_24();

class Base1
{
public:
    Base1() { cout << x << "\n"; }
    virtual inline std::ostream &print()
    {
        std::cout << x << "\n";
        return std::cout;
    }
    virtual ~Base1()
    {
        std::cout << "base1 dctr\n";
    }

private:
    int x = 4;
};

class D1 : public Base1
{
public:
    inline std::ostream &print() override
    {
        std::cout << "d1 from base1 \n";
        return std::cout;
    }
    ~D1()
    {
        std::cout << "d1 from base1 dctr\n";
    }
};

class Base2
{
public:
    Base2() { cout << y << "\n"; }
    virtual inline std::ostream &print()
    {
        std::cout << y << "\n";
        return std::cout;
    }
    virtual ~Base2()
    {
        std::cout << "base2 dctr\n";
    }

private:
    int y = 5;
};

class D2 : public Base2
{
public:
    inline std::ostream &print() override
    {
        std::cout << "d2 from base2 \n";
        return std::cout;
    }
    ~D2()
    {
        std::cout << "d2 from base2 dctr\n";
    }
};

class MI2 : public D1, public D2
{
    inline std::ostream &print() override
    {
        std::cout << "mi2 from d1 and d2 \n";
        return std::cout;
    }
};

// Exercise 18.25: Assume we have two base classes, Base1 and Base2,
// each of which defines a virtual member named print and a virtual destructor.
// From these base classes we derive the following classes, each of
// which redefines the print function:
// class D1 : public Base1 { /* ... */ };
// class D2 : public Base2 { /* ... */ };
// class MI : public D1, public D2 { /* ... */ };
// Using the following pointers, determine which function is used in each call:
// Base1 *pb1 = new MI;
// Base2 *pb2 = new MI;
// D1 *pd1 = new MI;
// D2 *pd2 = new MI;
// (a) pb1->print();
// (b) pd1->print();
// (c) pd2->print();
// (d) delete pb2;
// (e) delete pd1;
// (f) delete pd2;
int exercise18_25();

struct AnotherBase1
{
    inline void print(int temp) const { std::cout << temp << "\n"; }; // public by default
protected:
    int ival;
    double dval;
    char cval;

private:
    int *id;
};

struct AnotherBase2
{
    inline void print(double temp) const { std::cout << temp << "\n"; }; // public by default
protected:
    double fval;

private:
    double dval;
};

struct Derived : public AnotherBase1
{
    inline void print(std::string temp) const { std::cout << temp << "\n"; }; // public by default
protected:
    std::string sval;
    double dval;
};

struct MI3 : public Derived, public AnotherBase2
{
    inline void print(std::vector<double> temp) { rangeForContainer(temp); }; // public by default
    inline void foo(double cval)
    {
        int dval(211);
        cout << ", " << ival << ", " << dval << ", " << cval << ", " << sval << ", " << fval << "\n";

        dval = AnotherBase1::dval + Derived::dval;

        cout << AnotherBase1::dval << ", " << Derived::dval << ", " << dval << "\n";

        dvec = {2.1, 2.2, 2.3};
        fval = dvec.back();

        rangeForContainer(dvec);
        cout << fval << "\n";

        AnotherBase1::cval = 'd';
        sval = std::string("abc");
        cout << sval << "\n"
             << AnotherBase1::cval << "\n";

        *(sval.begin()) = AnotherBase1::cval;
        cout << sval << "\n";
    }

protected:
    int *ival;
    std::vector<double> dvec;
};

// Exercises Section 18.3.3
// Exercise 18.26: Given the hierarchy in the box on page 810, why is the
// following call to print an error? Revise MI to allow this call to print to
// compile and execute correctly.
// MI mi;
// mi.print(42);
int exercise18_26();

// Exercise 18.27: Given the class hierarchy in the box on page 810 and
// assuming we add a function named foo to MI as follows:
// int ival;
// double dval;
// void MI::foo(double cval)
// {
//  int dval;
//  // exercise questions occur here
// }
// (a) List all the names visible from within MI::foo.
// (b) Are any names visible from more than one base class?
// (c) Assign to the local instance of dval the sum of the dval member of
// Base1 and the dval member of Derived.
// (d) Assign the value of the last element in MI::dvec to Base2::fval.
// (e) Assign cval from Base1 to the first character in sval from Derived.
int exercise18_27();

struct ThisBase
{
    inline void bar(int temp) { cout << "ThisBase " << temp << "\n"; }; // public by default
protected:
    int ival{20};
};

struct ThisDerived1 : virtual public ThisBase
{
    inline void bar(char temp) { cout << "ThisDerived1 " << temp << "\n"; }; // public by default
    inline void foo(char temp) { cout << "ThisDerived1 " << temp << "\n"; };

protected:
    char cval{'d'};
};

struct ThisDerived2 : virtual public ThisBase
{
    inline void foo(int temp) { cout << "ThisDerived2 " << temp << "\n"; }; // public by default
protected:
    int ival{10};
    char cval{'c'};
};

class VMI : public ThisDerived1, public ThisDerived2
{
};

// Exercises Section 18.3.4
// Exercise 18.28: Given the following class hierarchy, which inherited
// members can be accessed without qualification from within the VMI class?
// Which require qualification? Explain your reasoning.
int exercise18_28();

class FinalClass
{
public:
    FinalClass() { cout << "FinalClass ctr\n"; }
    virtual inline int get() { return a; }
    ~FinalClass() { cout << "FinalClass dctr\n"; }

private:
    int a{1};
};

class FinalBase : public FinalClass
{
public:
    FinalBase() { cout << "FinalBase ctr\n"; }
    FinalBase(const FinalBase &temp)
    {
        b = temp.b;
        cout << "FinalBase copy ctr\n";
    }
    FinalBase(int temp)
    {
        b = temp;
        cout << "FinalBase int ctr\n";
    }
    virtual inline int get() { return b; }
    ~FinalBase() { cout << "FinalBase dctr\n"; }

private:
    int b{2};
};

class FinalD1 : virtual public FinalBase
{
public:
    FinalD1() { cout << "FinalD1 ctr\n"; }
    FinalD1(const FinalD1 &temp) : FinalBase(temp)
    {
        c = temp.c;
        cout << "FinalD1 copy ctr\n";
    }
    FinalD1(int temp1, int temp2) : FinalBase(temp1)
    {
        c = temp2;
        cout << "FinalD1 int ctr\n";
    }
    virtual inline int get() { return c; }
    ~FinalD1() { cout << "FinalD1 dctr\n"; }

private:
    int c{3};
};

class FinalD2 : virtual public FinalBase
{
public:
    FinalD2() { cout << "FinalD2 ctr\n"; }
    FinalD2(const FinalD2 &temp) : FinalBase(temp)
    {
        d = temp.d;
        cout << "FinalD2 copy ctr\n";
    }
    FinalD2(int temp1, int temp2) : FinalBase(temp1)
    {
        d = temp2;
        cout << "FinalD2 int ctr\n";
    }

    virtual inline int get() { return d; }
    ~FinalD2() { cout << "FinalD2 dctr\n"; }

private:
    int d{4};
};

class FinalMI : public FinalD1, public FinalD2
{
public:
    FinalMI() { cout << "FinalMI ctr\n"; }
    FinalMI(int t1, int t2, int t3) : FinalBase(t1), FinalD1(t1, t2), FinalD2(t1, t3) { cout << "FinalMI ctr\n"; }
    virtual inline int get()
    {
        cout << static_cast<FinalBase>(*this).get() << ", "
             << static_cast<FinalD1>(*this).get() << ", "
             << static_cast<FinalD2>(*this).get() << ", "
             << e << "\n";
        return e;
    }
    ~FinalMI() { cout << "FinalMI dctr\n"; }

private:
    int e{5};
};

class FinalFinal : public FinalMI, public FinalClass
{
public:
    FinalFinal() { cout << "FinalFinal ctr\n"; }
    virtual inline int get() { return f; }
    ~FinalFinal() { cout << "FinalFinal dctr\n"; }

private:
    int f{6};
};

// Exercises Section 18.3.5
// Exercise 18.29: Given the following class hierarchy:
// class Class { ... };
// class Base : public Class { ... };
// class D1 : virtual public Base { ... };
// class D2 : virtual public Base { ... };
// class MI : public D1, public D2 { ... };
// class Final : public MI, public Class { ... };
// (a) In what order are constructors and destructors run on a Final object?
// (b) A Final object has how many Base parts? How many Class parts?
// (c) Which of the following assignments is a compile-time error?
// Base *pb; Class *pc; MI *pmi; D2 *pd2;
// (a) pb = new Class;
// (b) pc = new Final;
// (c) pmi = pb;
// (d) pd2 = pmi;
int exercise18_29();

// Exercise 18.30: Define a default constructor, a copy constructor, and a
// constructor that has an int parameter in Base. Define the same three
// constructors in each derived class. Each constructor should use its argument
// to initialize its Base part.
int exercise18_30();

#endif